#!/usr/bin/python3
# -*- coding:utf-8 -*-
"""
@File: SystemJobsRun.py
@Author: lijk34925 
@Date: 2024/8/8 20:09
@desc: 请补充本模块功能说明
"""
import json
import os
import re
from datetime import datetime

import jsonpath
from qturboframe.lib.utils.variable import Variable
from qturboframe.lib.webdriver import SeleniumError

from AmlScripts.amlConfig import amlConfig
from CommonScripts.index_rule_cal import indexJobAction, httpRequest
from BladeFerm.Lib.Common import logger
from BladeFerm.utils.dataoperation import YamlOperation
from BladeFerm.databases import DB_APP


def run_total_job_flow(input_data=None, ui_expect=None):
    """
    运行日终任务流：
        1.执行SQL设置 前置任务或前一天任务 的完成标识；
        2.执行日终任务
    :param occur_date:
    :param server_name: 调度系统的日终任务名称
    :return:
    """
    server_name = input_data.get("server_name")
    occur_date = input_data.get("occur_date", datetime.today().strftime("%Y%m%d"))
    blade_verb = Variable()
    env = blade_verb.get_variable('varg_db_type')
    env = 'oracle' if env == 'AGENT_EMPTY' or env is None else env
    config = amlConfig.get(env)
    logger.info(f"{config} 环境的系统参数是：{config}")
    # 0.获取当前脚本的绝对路径，读取日终任务运行配置
    current_path = os.path.abspath(__file__)
    current_dir = os.path.dirname(current_path)
    etl_config_path = os.path.join(current_dir, "SystemJobsRunConfig.yaml")
    etl_dict = YamlOperation(etl_config_path).readYaml()
    etl_json = etl_dict.get("ETL_JOB")
    etl_data = etl_dict.get("ETL_RUN_CONDITION")
    # 0.获取近期的交易日列表
    trade_days = __check_params(server_name, occur_date, etl_json)
    if not trade_days:
        return False
    servers = server_name.replace("，", ",").split(",")
    for i, name in enumerate(servers):
        etl_job = etl_json.get(name)
        logger.info(f"开始执行 {name} 任务，任务参数：{etl_job}")
        stop_jobs = etl_job.get("stop_jobs", None)
        clear_table_data = etl_job.get("clear_table_data", None)
        check_server_flag = etl_job.get("check_data", None)
        before_servers = etl_job.get("before_data", None)
        if stop_jobs:           # 1.停止前置无关的job
            stop_job_list = stop_jobs.replace("，", ",").split(",")
            for job_n in stop_job_list:
                before_etl_params = etl_json.get(job_n)
                __stop_job(before_etl_params, env)
        if clear_table_data:    # 2.清理数据，提高执行效率
            for d_sql in clear_table_data:
                DB_APP.run_one_sql(d_sql)
        if check_server_flag and i == 0:   # 3.设置任务运行检查前置任务的完成标识
            __insert_flag(occur_date, check_server_flag, etl_data)
        if before_servers:      # 4.设置任务运行检查当前任务前一天完成标识
            before_server_flags = before_servers.split(",")
            for server_flag in before_server_flags:
                index = trade_days.index(int(occur_date))
                before_date = trade_days[index-1]
                __insert_flag(before_date, server_flag, etl_data)
        logger.info(f"{name} 任务 {occur_date} 日的标识设置完成！可以开始执行任务了！")
        result = __act_job(occur_date, env, etl_job)     # 5.运行日终任务
        expect_result = ui_expect.get("result", True)
        if expect_result and result == bool(expect_result):
            logger.info(f"{name} 任务运行成功！")
        else:
            raise SeleniumError(f"{name} 任务运行失败，请检查！")


def __check_params(server_name, occur_date, etl_json):
    """
    入参检查，并返回系统交易日列表
    :param server_name:
    :param occur_date:
    :param db:
    :return:
    """
    expect_server_names = list(etl_json.keys())
    if server_name not in expect_server_names:
        error = f"输入参数 [{server_name}] 错误，不在期望入参 {expect_server_names} 中，请检查！"
        logger.error(error)
        raise SeleniumError(error)
    begin_date, end_date = int(occur_date)-7, int(occur_date)+7
    trade_day_sql = (f"SELECT OCCUR_DATE  FROM HSPBS.SYS_TRADE_DAY t "
                     f"WHERE t.IS_SHSZ_EXCHDATE = '1' and t.OCCUR_DATE > {begin_date} and t.OCCUR_DATE<{end_date}")
    result = DB_APP.run_one_sql(trade_day_sql)
    days = jsonpath.jsonpath(result, "$..OCCUR_DATE")
    if days and int(occur_date) in days:
        logger.info(f"获取 {occur_date} 附近的交易日有：{days}")
        return days
    else:
        error = f"输入参数 [{occur_date}] 错误，不在系统交易日中，请检查！"
        logger.error(error)
        raise SeleniumError(error)


def __insert_flag(occur, server, etl_data):
    """
    获取设置日终任务标志的SQL语句
    :param occur:
    :param server:
    :return:
    """
    etl = etl_data.get(server.upper())
    table = etl.pop("TABLE")
    if re.search(r"SYS_ETL_LOG", table, re.I):
        select_sql = f"select MAX(ROW_ID) AS MAX_ROW_ID from {table}"
        select_result = DB_APP.run_one_sql(select_sql)
        max_row_id = select_result[0].get("MAX_ROW_ID")
        if max_row_id is None:
            max_row_id = 0
        etl.update({"OCCUR_DATE": occur, "ROW_ID": int(max_row_id) + 1})
    else:
        etl.update({"init_date": occur})
    keys = ",".join(list(etl.keys()))
    values = str(list(etl.values()))[1:-1]
    insert_sql = f"insert into {table}({keys}) values ({values})"
    logger.info(f"Insert sql: {insert_sql}")
    DB_APP.run_one_sql(insert_sql)
    logger.info(f"Insert flag: [{occur}-{server}] success.")
    return True


def __act_job(occur_date, env, job_dict):
    """
    执行日终任务
    :param occur_date:
    :param job_dict:
    :param env:
    :return:
    """
    job_id = job_dict.get("job_id")
    job_params = job_dict.get("job_params")
    job_timeout = job_dict.get("job_timeout", 300)
    task_params = {}
    index = 0
    for k, v in job_params.items():
        if k in ["p_init_date", "p_begin_date", "p_end_date"]:
            temp_params = {"name": k, "value": str(occur_date), "custom": True, "direct": "", "index": index}
        else:
            temp_params = {"name": k, "value": str(v), "custom": True, "direct": "", "index": index}
        task_params[k] = temp_params
        index += 1
    job_input_data = {'jobName': job_id, 'taskParam': json.dumps(task_params), 'env': env,
                      'max_times': job_dict.get("job_timeout", job_timeout)}
    logger.info(f"Job {job_id} start run. params: {job_input_data}")
    result = indexJobAction(input_data=job_input_data)
    return result


def __stop_job(etl_job, env):
    """
    停止任务
    :param job_id:
    :param env:
    :return:
    """
    job_input_data = {'env': env,
                      'url': '/scheduler/timertask/pauseTask.json',
                      'type': 'GET',
                      'headers': {'Content-type': 'application/x-www-form-urlencoded;charset=UTF-8'},
                      'data': {'jobName': etl_job.get('job_id'), 'jobGroup': 'default'}}
    httpRequest(input_data=job_input_data)
